/**
 * Dessine le graphique d'une unique cotation
 * La cotation peut être accompagnée d'indicateurs
 */

package com.miage.itrading.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.DateRange;
import com.google.gwt.visualization.client.events.RangeChangeHandler;
import com.google.gwt.visualization.client.visualizations.AnnotatedTimeLine;
import com.google.gwt.visualization.client.visualizations.corechart.ColumnChart;
import com.miage.itrading.client.GraphDurees.Duree;
import com.miage.itrading.shared.entites.Cotation;
import com.miage.itrading.shared.entites.Historique;
import com.miage.itrading.shared.entites.Intraday;

// TODO : Vérification / merge des historiques de la cotation 

@SuppressWarnings("deprecation")
public class GraphWidget extends GenericWidget {

	private static final int														WIDTH				= 600;

	private final GetListesServiceAsync												getListesService	= GWT
																												.create(GetListesService.class);

	private Widget																	retour				= null;

	private AnnotatedTimeLine														annotatedChart;
	private ColumnChart																columnChart;
	private DataTable																dataColumnChart;

	private com.google.gwt.visualization.client.visualizations.corechart.Options	optionsColumnChart;

	private Cotation																cotation;
	private ArrayList<String>														nomsIndicateurs;
	private ArrayList<ArrayList<Float>>												valeursIndicateurs;

	public GraphWidget(ItradingAffichage context, String uid) {
		super(context, uid);
		cotation = new Cotation();
		nomsIndicateurs = new ArrayList<String>();
		valeursIndicateurs = new ArrayList<ArrayList<Float>>();

	}

	public void ajouter(String nomIndicateur, List<Float> valeurs) {
		nomsIndicateurs.add(nomIndicateur);
		valeursIndicateurs.add((ArrayList<Float>) valeurs);
	}

	public Widget build() {
		return build(Duree.INTRADAY);
	}

	/**
	 * Construit un graphique de "dateDebut" à "dateFin", définit les valeurs
	 * "courbes" correspondant aux courbes "noms"
	 * 
	 * @param typeGraphe
	 * @return
	 */
	public Widget build(Duree duree) {

		if (cotation == null) {
			return new VerticalPanel();
		} else {

			final RangeChangeHandler rangeChange = new RangeChangeHandler() {
				public void onRangeChange(RangeChangeEvent event) {

					/**
					 * Le range de référence est dataColumnChart, on affiche maintenant un
					 * sous-ensemble
					 */
					DateRange range = annotatedChart.getVisibleChartRange();

					boolean withinRange = false;

					DataTable dataColumnChart2 = DataTable.create();
					int iRow = 0;

					for (int i = 0; i < dataColumnChart.getNumberOfRows(); ++i) {

						/**
						 * Début d'affichage
						 */
						if (dataColumnChart.getValueDate(i, 0).equals(
								range.getStart())) {
							withinRange = true;

							/**
							 * On sort du range d'affichage
							 */
						} else if (dataColumnChart.getValueDate(i, 0).after(
								range.getEnd())) {
							withinRange = false;
						}

						if (withinRange) {
							dataColumnChart2.addRow();
							dataColumnChart2.setValue(iRow, 0, dataColumnChart
									.getValueDate(0, 1));
							dataColumnChart2.setValue(iRow, 1, dataColumnChart
									.getValueInt(i, 1));

							++iRow;
						}
					}

					columnChart = new ColumnChart(dataColumnChart2,
							optionsColumnChart);
					columnChart.setVisible(true);
				}
			};

			System.out.println("Durée : " + duree);

			/**
			 * Vérifie que l'historique de la cotation contient assez de données pour être affiché
			 * en
			 * entier, sinon va chercher les x valeurs manquantes
			 */
			if (duree == Duree.INTRADAY) {
				final AsyncCallback<List<Intraday>> intradayCallback = new AsyncCallback<List<Intraday>>() {

					public void onFailure(Throwable caught) {
						Window.alert("Erreur lors de l'appel serveur "
								+ caught.getMessage());

					}

					public void onSuccess(List<Intraday> result) {
						System.out.println("Intraday : got the list!");
						retour = buildIntraday(result);

						System.out.println("Intraday : built the graph!");

						/**
						 * Le zoom n'est géré nativement que pour la time line,
						 * on recréé le graphique des volumes à la volée
						 */
						annotatedChart.addRangeChangeHandler(rangeChange);

						System.out
								.println("Intraday : added the change handler!");
					}
				};

				getListesService.getIntraday(cotation.getIdCotation(), null,
						intradayCallback);
			} else {

				final AsyncCallback<List<Historique>> historiqueCallback = new AsyncCallback<List<Historique>>() {

					public void onFailure(Throwable caught) {
						Window.alert("Erreur lors de l'appel serveur "
								+ caught.getMessage());

					}

					public void onSuccess(List<Historique> result) {
						System.out.println("Build historique sur "
								+ result.size());
						retour = buildHistorique(result);

						annotatedChart.addRangeChangeHandler(rangeChange);
					}
				};

				Date ajd = new Date();

				if (duree == Duree.SEMAINE) {
					Date cinqJours = new Date();
					cinqJours.setDate(cinqJours.getDate() - 5);
					getListesService.getHistorique(cotation.getIdCotation(),
							cinqJours, ajd, historiqueCallback);

				} else if (duree == Duree.MOIS) {
					Date unMois = new Date();
					unMois.setMonth(unMois.getMonth() - 1);
					getListesService.getHistorique(cotation.getIdCotation(),
							unMois, ajd, historiqueCallback);

				} else if (duree == Duree.ANNEE) {

					Date unAn = new Date();
					unAn.setYear(unAn.getYear() - 1);
					getListesService.getHistorique(cotation.getIdCotation(),
							unAn, ajd, historiqueCallback);

				} else if (duree == Duree.HISTORIQUE) {
					getListesService.getHistorique(cotation.getIdCotation(),
							null, null, historiqueCallback);
				}
			}

			return retour;
		}
	}

	private Widget buildHistorique(List<Historique> historique) {
		VerticalPanel graphs = new VerticalPanel();

		int nbHistoriques = historique.size();

		System.out.println("Historique : " + nbHistoriques);

		// /**
		// * Annotated Time Line : cours
		// */
		// Options options = Options.create();
		// options.setDisplayAnnotations(true);
		// options.setDisplayZoomButtons(true);
		// options.setScaleType(AnnotatedTimeLine.ScaleType.ALLFIXED);
		// options
		// .setLegendPosition(AnnotatedTimeLine.AnnotatedLegendPosition.SAME_ROW);
		//
		// DataTable data = DataTable.create();
		// data.addColumn(AbstractDataTable.ColumnType.DATE, "Date");
		// data.addColumn(AbstractDataTable.ColumnType.NUMBER, "Cours");
		//
		// /**
		// * ColumnChart : volume
		// */
		// optionsColumnChart = com.google.gwt.visualization.client.visualizations.corechart.Options
		// .create();
		// optionsColumnChart.setWidth(600);
		// optionsColumnChart.setHeight(200);
		//
		// dataColumnChart = DataTable.create();
		// dataColumnChart.addColumn(AbstractDataTable.ColumnType.DATE, "Date");
		// dataColumnChart.addColumn(AbstractDataTable.ColumnType.NUMBER, "Cours");
		//
		// if (nbHistoriques > 0) {
		// data.addRows(nbHistoriques);
		// dataColumnChart.addRows(nbHistoriques);
		// }
		//
		// try {
		// Historique cotationJour;
		// Date dateCotation;
		//
		// for (int i = 0; i < nbHistoriques; ++i) {
		// cotationJour = cotation.getHistoriques().get(i);
		//
		// dateCotation = new Date(cotationJour.getDate().getTime());
		// dateCotation.setMinutes(0);
		// dateCotation.setHours(0);
		// dateCotation.setSeconds(0);
		//
		// data.setValue(i, 0, dateCotation);
		// data.setValue(i, 1, cotationJour.getFermeture());
		//
		// dataColumnChart.setValue(i, 0, dateCotation);
		// dataColumnChart.setValue(i, 1, cotationJour.getVolume());
		// }
		// } catch (Exception e) {
		// System.out
		// .println("Erreur lors de la construction du graphique de "
		// + cotation.getNom());
		// }
		//
		// // /**
		// // * Ajoute deux évènements au 15ème jour
		// // */
		// // data.setValue(15, 2, "Event1");
		// // data.setValue(15, 4, "Event2");
		//
		// annotatedChart = new AnnotatedTimeLine(data, options, WIDTH + "px",
		// "500px");
		// annotatedChart.setVisible(true);
		//
		// columnChart = new ColumnChart(dataColumnChart, optionsColumnChart);
		// columnChart.setVisible(true);
		//
		// graphs.add(annotatedChart);
		// graphs.add(columnChart);

		return graphs;
	}

	private Widget buildIntraday(List<Intraday> tempsReel) {
		VerticalPanel graphs = new VerticalPanel();

		int nbHistoriques = tempsReel.size();

		System.out.println("Intraday : intraday " + nbHistoriques);

		// /**
		// * Annotated Time Line : cours
		// */
		// Options options = Options.create();
		// options.setDisplayAnnotations(true);
		// options.setDisplayZoomButtons(true);
		// options.setScaleType(AnnotatedTimeLine.ScaleType.ALLFIXED);
		// options
		// .setLegendPosition(AnnotatedTimeLine.AnnotatedLegendPosition.SAME_ROW);
		//
		// DataTable data = DataTable.create();
		// data.addColumn(AbstractDataTable.ColumnType.DATETIME, "Date");
		// data.addColumn(AbstractDataTable.ColumnType.NUMBER, "Cours");
		//
		// /**
		// * ColumnChart : volume
		// */
		// optionsColumnChart = com.google.gwt.visualization.client.visualizations.corechart.Options
		// .create();
		// optionsColumnChart.setWidth(600);
		// optionsColumnChart.setHeight(200);
		//
		// dataColumnChart = DataTable.create();
		// dataColumnChart
		// .addColumn(AbstractDataTable.ColumnType.DATETIME, "Date");
		// dataColumnChart.addColumn(AbstractDataTable.ColumnType.NUMBER, "Cours");
		//
		// if (tempsReel.size() > 0) {
		//
		// /**
		// * Construit un graphique minute par minute, de 09:00 jusqu'à 17:35
		// */
		// int nbRows;
		// nbRows = (int) ((Const.HEURE_FERMETURE.getTime() - Const.HEURE_OUVERTURE
		// .getTime()) / (60 * 1000));
		//
		// System.out.println("nbRows intraday: " + nbRows);
		// data.addRows(nbRows);
		// dataColumnChart.addRows(nbRows);
		//
		// try {
		// /**
		// * Première valeur du jour
		// */
		// boolean trouveNouvelleValeur = false;
		// long differenceCotationMinuteActuelle;
		//
		// int iValeur = 0;
		// Intraday valeur = null;
		// if (tempsReel.size() > 0) {
		// valeur = tempsReel.get(iValeur);
		// }
		//
		// /**
		// * Initialise la timeline à ajd, 9:00
		// */
		// Date timeline = new Date();
		// timeline.setHours(Const.HEURE_OUVERTURE.getHours());
		// timeline.setMinutes(Const.HEURE_OUVERTURE.getMinutes());
		//
		// for (int i = 0; i < nbRows; ++i) {
		//
		// /**
		// * Affiche la valeur de la cotation si sa date et la minute affichée sont les
		// * plus
		// * rapprochées
		// */
		// if (valeur != null) {
		// differenceCotationMinuteActuelle = (valeur.getDate()
		// .getTime() - timeline.getTime());
		//
		// System.out.println("différence minute : "
		// + differenceCotationMinuteActuelle);
		//
		// if (Math.abs(differenceCotationMinuteActuelle) < 30000) {
		// data.setValue(i, 1, valeur.getCotation());
		// dataColumnChart
		// .setValue(i, 1, valeur.getCotation());
		//
		// iValeur++;
		//
		// if (tempsReel.size() > iValeur) {
		// valeur = tempsReel.get(iValeur);
		// } else {
		// valeur = null;
		// }
		// }
		// /**
		// * La cotation courante est trop ancienne, on passe aux suivantes jusqu'à
		// * temps
		// * d'en trouver une qui soit dans la timeline
		// */
		// else if (differenceCotationMinuteActuelle < 0) {
		// trouveNouvelleValeur = false;
		//
		// while (tempsReel.size() > iValeur) {
		// iValeur++;
		// valeur = tempsReel.get(iValeur);
		//
		// /**
		// * Il faut que la date de la cotation soit au moins 30 seconde après
		// * la
		// * date actuelle pour être prise en compte par la prochaine date
		// */
		// if ((valeur.getDate().getTime() - timeline
		// .getTime()) > 30000) {
		// trouveNouvelleValeur = true;
		// break;
		// }
		// }
		//
		// if (trouveNouvelleValeur == false) {
		// valeur = null;
		// }
		// }
		// }
		//
		// data.setValue(i, 0, timeline);
		// dataColumnChart.setValue(i, 0, timeline);
		//
		// // Ajoute une minute = 60,000 ms
		// timeline.setTime(timeline.getTime() + 60000);
		// }
		// } catch (Exception e) {
		// System.out
		// .println("Erreur lors de la construction du graphique de "
		// + cotation.getNom());
		//
		// e.printStackTrace();
		// }
		// }
		// // /**
		// // * Ajoute deux évènements au 15ème jour
		// // */
		// // data.setValue(15, 2, "Event1");
		// // data.setValue(15, 4, "Event2");
		//
		// annotatedChart = new AnnotatedTimeLine(data, options, WIDTH + "px",
		// "500px");
		// annotatedChart.setVisible(true);
		//
		// columnChart = new ColumnChart(dataColumnChart, optionsColumnChart);
		// columnChart.setVisible(true);
		//
		// graphs.add(annotatedChart);
		// graphs.add(columnChart);

		return graphs;
	}

	public void clear() {
		annotatedChart.setVisible(false);

		cotation = new Cotation();
		nomsIndicateurs = new ArrayList<String>();
		valeursIndicateurs = new ArrayList<ArrayList<Float>>();
	}

	public void configureWidget() {

	}

	public Widget createWidget() {

		VerticalPanel bump = new VerticalPanel();
		bump.setWidth(WIDTH + "px");

		return bump;
	}

	public Cotation getCotation() {
		return cotation;
	}

	public void setCotation(Cotation c) {
		cotation = c;
	}

	public void setSize(String w, String h) {
		if (annotatedChart != null) {
			annotatedChart.setSize(w, h);
		}
	}
}
